package com.flex.reflection.invoke;

import com.flex.reflection.MetaField;
import com.flex.reflection.MetaClass;
import com.flex.reflection.listener.PropertyListener;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.List;

/**
 * @author ganlt
 * @since 2019/09/20 13:12
 */
public class InvokeProperty implements Invoke {
    private MetaField metaField;
    private PropertyListener propertyListener;

    public InvokeProperty(MetaField field){
        this.metaField = field;
    }

    public InvokeProperty(MetaField field, PropertyListener propertyListener) {
        this(field);
        this.propertyListener = propertyListener;
    }

    @Override
    public Object invoke(Object target, Object[] args) throws IllegalAccessException {
        if (args!= null && args.length>1) {
            throw new IllegalArgumentException("property 属性不能设置多个参数");
        }
        Field field = metaField.getField();
        if (args!=null && args.length > 0) {
            try {
                Object newVal = args[0];
                updateField(metaField,newVal);
            } catch (IllegalAccessException e) {
                if (MetaClass.canControlMemberAccessible()) {
                    field.setAccessible(true);
                    Object newVal = args[0];
                    updateField(target,newVal);
                } else {
                    throw e;
                }
            }
        }
        try {

            Object val = field.get(target);
            if (propertyListener!=null && (args==null || args.length==0 ) ) {
                propertyListener.readProperty(field.getName(), val);
            }
            return val;
        } catch (IllegalAccessException e) {
            if (MetaClass.canControlMemberAccessible()) {
                field.setAccessible(true);
                Object val = field.get(target);
                if (propertyListener!=null && (args==null || args.length==0)) {
                    propertyListener.readProperty(field.getName(), val);
                }
                return val;
            } else {
                throw e;
            }
        }

    }

    private void updateField(Object target, Object newVal) throws IllegalAccessException {
        metaField.invoke(newVal, propertyListener);
    }

    @Override
    public List<Type> parameterType() {
        return null;
    }

    @Override
    public Type returnType() {
        return metaField.returnType();
    }


}
